import base64
import io
import os.path
import random
import time

from PIL import Image
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.edge.options import Options
from selenium.webdriver.edge.service import Service

from SlideVerifyCode import SlideVerifyCode
from selenium_utils import SeleniumUtils


# https://blog.51cto.com/u_16099273/6555715
class Jianshu:
    def __init__(self):
        # 尝试传参
        s = Service("../chromedriver.exe")
        options = Options()
        # options.add_experimental_option('excludeSwitches', ['enable-automation'])
        # options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")  # 前面设置的端口号
        self.driver = webdriver.Chrome(service=s)
        self.driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
            "source": """
            Object.defineProperty(navigator, 'webdriver', {
              get: () => undefined
            })
          """
        })
        # self.driver = webdriver.Chrome(service=s, options=chrome_options)
        # driverfile_path = r'./msedgedriver.exe'
        # driver = webdriver.Edge(executable_path=driverfile_path)
        self.driver.maximize_window()  # 最大化窗口

        # 4.3计算滑动距离
        self.sc = SlideVerifyCode()
        self.crack_count = 0

    def start(self, cover, title, desc):
        try:
            # 进入创作者页面
            self.driver.get(
                "https://www.jianshu.com/writer#/notebooks/54553102/notes/116733699?" + str(random.random()))
            self.driver.implicitly_wait(5)
            if os.path.exists("../cookies/jianshu.pkl"):
                SeleniumUtils.load_cookie(self.driver, ".jianshu.com", "../cookies/jianshu.pkl")
                self.driver.refresh()

            SeleniumUtils.watting_visibility(self.driver, By.TAG_NAME, "body")
            is_load = SeleniumUtils.is_loaded(self.driver)
            if not is_load:
                print("页面加载失败！")
                return "页面加载失败"
            e_login = None
            try:
                e_login = SeleniumUtils.watting_existed(self.driver, By.XPATH,
                                                        "/html/body/div[1]/div[2]/div[2]/h4/div/a[1]")
            except Exception as e:
                print(e)

            if e_login is not None:
                return self.do_login(cover, title, desc)
            # else:
            #     return self.do_publish(cover, title, desc)
        except Exception as e:
            print(e)
            self.driver.quit()
            return e

    def do_login(self, cover, title, desc):
        self.driver.find_element(By.XPATH,
                                 value="//*[@id='session_email_or_mobile_number']").send_keys(
            "xxxxxxxxxxx")
        self.driver.find_element(By.XPATH,
                                 "//*[@id='session_password']").send_keys(
            "xxxxxxxxxxx")
        time.sleep(2)
        SeleniumUtils.move_click_by(self.driver, By.XPATH,
                                    "//*[@id='sign-in-form-submit-btn']",
                                    5)

        ele_pop = SeleniumUtils.watting_visibility(self.driver, By.XPATH,
                                                   "/html/body/div[3]/div[2]/div[6]/div/div[1]/div[1]/div/a/div[1]/div/canvas[1]",
                                                   5)

        if ele_pop is None or not ele_pop.is_displayed():
            return "破解验证码失败"
        ret = self.crack_slide_code(cover, title, desc)

        if ret != 0:
            return "破解验证码失败"
        # cookie.pkl文件
        SeleniumUtils.save_cookie(self.driver, "../cookies/jianshu.pkl")
        return self.do_publish(cover, title, desc)

    def crack_slide_code(self, cover, title, desc):
        try:
            print("开始第{}次验证码破解".format(self.crack_count))
            time.sleep(2)
            # 4.2 获取滑动相关的元素
            # 选择拖动滑块的节点
            slide_element = self.driver.find_element(By.XPATH,
                                                     '/html/body/div[3]/div[2]/div[6]/div/div[1]/div[2]/div[2]')

            # 下面的js代码根据canvas文档说明而来
            # JS = 'return document.getElementById("captcha-verify-image").toDataURL("image/png");'
            # # 执行 JS 代码并拿到图片 base64 数据
            # im_info = self.driver.execute_script(JS)  # 执行js文件得到带图片信息的图片数据
            # im_base64 = im_info.split(',')[1]  # 拿到base64编码的图片信息
            # im_bytes = base64.b64decode(im_base64)  # 转为bytes类型
            # with open('./images/toutiao.png', 'wb') as f:  # 保存图片到本地
            #     f.write(im_bytes)
            canvas = self.driver.find_element(By.XPATH,
                                              "/html/body/div[3]/div[2]/div[6]/div/div[1]/div[1]/div/a/div[1]/div/canvas[1]")
            canvas_data = self.driver.execute_script('return arguments[0].toDataURL("image/png").substring(21);',
                                                     canvas)

            # 将画面数据转换为图片
            image_data = base64.b64decode(canvas_data)
            image = Image.open(io.BytesIO(image_data))

            # 指定图片大小
            new_image = image.resize((260, 160))  # 替换为你想要的图片大小

            # 保存图片
            new_image.save('./images/jianshu.png')

            distance = self.sc.get_image_slide_distance(None, None, './images/jianshu.png')
            if distance == -1 and self.crack_count < 2:  # 再一次验证
                self.crack_count += 1
                return self.crack_slide_code(cover, title, desc)
            # 滑动距离误差校正，滑动距离*图片在网页上显示的缩放比-滑块相对的初始位置
            print("校正后的滑动距离", distance)
            # 4.4、进行滑动
            ret = self.sc.slide_verification(self.driver, slide_element, distance - 10)
            # if ret == -1 and self.crack_count < 2:  # 在一次验证
            #     self.crack_count += 1
            #     return self.crack_slide_code(cover, title, theme, desc)
            return 0
        except Exception:
            if self.crack_count < 2:  # 在一次验证
                self.crack_count += 1
                return self.crack_slide_code(cover, title, desc)
        return -1

    def do_publish(self, cover, title, desc):
        try:
            SeleniumUtils.move_click_by(self.driver, By.XPATH, "/html/body/nav/div/a[2]")
        except:
            pass

        ele_new=SeleniumUtils.watting_visibility(self.driver,By.XPATH,"//*[@id='root']/div/div[2]/div[1]/div/div/div/div[1]")
        if ele_new is None or not ele_new.is_displayed():
            return "登录失败！"
        SeleniumUtils.move_click_by(self.driver,ele_new)
        time.sleep(1)
        # 尝试保存时发生错误：我们检测到您此次登录异常，请您进行安全验证。，无法保存
        # 填充标题
        self.driver.find_element(By.XPATH,
                                 value="//*[@id='root']/div/div[2]/div[2]/div/div/div/div/input").send_keys(
            title)
        time.sleep(1)
        # 填充描述
        ele_desc = self.driver.find_element(By.XPATH,
                                            "//*[@id='editor']/div/p")
        ele_desc.send_keys(desc)

        time.sleep(2)

        # 发布文章
        SeleniumUtils.move_click_by(self.driver, By.XPATH,
                                    "//*[@id='root']/div/div[2]/div[2]/div/div/div/div/ul/li[1]")

        # 等待发布完成
        ret = SeleniumUtils.watting_visibility(self.driver, By.XPATH, "//*[@id='root']/div[2]/div[1]/div/a[2]",
                                               30)
        if ret is None:
            print("发布失败")
            return "发布失败"
        return ""


if __name__ == "__main__":
    jianshu = Jianshu()
    # 基本信息
    # 视频存放路径
    cover = r"C:\workspace\python\zimeiti\assets\1076.png"
    # cover = None
    title = "自动化测试开发"
    # 视频描述
    desc = "裸眼3D看蜘蛛侠 #搞笑 #电影 #视觉震撼"
    jianshu.start(cover, title, desc)
